/**
 * @version 2007-4-3
 * @author xalinx at gmail dot com
 */
package org.nanhill.wafer.client.hibernate;

import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.cache.Cache;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.Timestamper;
import org.nanhill.wafer.client.HsfayeWaferClient;
import org.nanhill.wafer.client.RemoteCacheException;
import org.nanhill.wafer.client.WaferClient;

/**
 * @version 2007-4-3
 * @author xalinx at gmail dot com
 * 
 */
/**
 * @author Marc
 * 
 */
public class WaferCache implements Cache {
	private static final Log log = LogFactory.getLog(WaferCache.class);

	private static final int SIXTY_THOUSAND_MS = 60000;

	private final static WaferClient wc = new HsfayeWaferClient();

	/**
	 * cache region name.
	 */
	private String regionName;

	/**
	 * cache live, seconds.
	 */
	private int liveTime;

	/**
	 * Creates a new Hibernate pluggable cache based on a cache name. <p/>
	 * 
	 * @param cache
	 *            The underlying EhCache instance to use.
	 */
	public WaferCache(String regionName) {
		this.regionName = regionName;
	}

	public WaferCache(String regionName, int liveTime) {
		this(regionName);
		this.liveTime = liveTime;
	}

	public Object get(Object key) throws CacheException {
		if (log.isDebugEnabled()) {
			log.debug("key:" + key);
		}

		if (key == null) {
			return null;
		}

		Object value;
		try {
			value = wc.get(regionName, key.toString());
		} catch (RemoteCacheException e) {
			throw new CacheException(e);
		}

		if (value == null) {
			if (log.isDebugEnabled()) {
				log.debug("no item, key:" + key);
			}
		}
		return value;

	}

	public Object read(Object key) throws CacheException {
		return get(key);
	}

	public void update(Object key, Object value) throws CacheException {
		put(key, value);
	}

	public void put(Object key, Object value) throws CacheException {
		try {
			wc.put(value.getClass().getCanonicalName(), key.toString(), value,
					liveTime);
		} catch (RemoteCacheException e) {
			throw new CacheException(e);
		}
	}

	public void remove(Object key) throws CacheException {
		try {
			wc.remove(regionName, key.toString());
		} catch (RemoteCacheException e) {
			throw new CacheException(e);
		}
	}

	public void clear() throws CacheException {
		try {
			wc.clear(regionName);
		} catch (RemoteCacheException e) {
			throw new CacheException(e);
		}
	}

	public void destroy() throws CacheException {
		clear();
	}

	public void lock(Object key) throws CacheException {
	}

	public void unlock(Object key) throws CacheException {
	}

	public long nextTimestamp() {
		return Timestamper.next();
	}

	public int getTimeout() {
		// 60 second lock timeout
		return Timestamper.ONE_MS * SIXTY_THOUSAND_MS;
	}

	public String getRegionName() {
		return regionName;
	}

	public long getSizeInMemory() {
		log.warn("cann't getSizeInMemory in memcached!");
		throw new CacheException("cann't getSizeInMemory in memcached!");
	}

	public long getElementCountInMemory() {
		long count;
		try {
			count = wc.count(regionName);
		} catch (RemoteCacheException e) {
			throw new CacheException(e);
		}
		if (log.isDebugEnabled()) {
			log.debug("items count:" + count);
		}
		return count;
	}

	public long getElementCountOnDisk() {
		log.warn("cann't getElementCountOnDisk in memcached!");
		throw new CacheException("cann't getElementCountOnDisk in memcached!");
	}

	public Map toMap() {
		log.warn("cann't toMap in memcached!");
		throw new CacheException("cann't toMap in memcached!");
	}

	public String toString() {
		return "WaferCache(" + getRegionName() + ')';
	}

}
